/**
 * 
 */
package de.htwg.ppt2html5.extraction;


import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;

import javax.imageio.ImageIO;

import org.docx4j.openpackaging.exceptions.Docx4JException;
import org.docx4j.openpackaging.exceptions.InvalidFormatException;
import org.docx4j.openpackaging.packages.PresentationMLPackage;
import org.docx4j.openpackaging.parts.DocPropsCorePart;
import org.docx4j.openpackaging.parts.Part;
import org.docx4j.openpackaging.parts.PartName;
import org.docx4j.openpackaging.parts.PresentationML.SlidePart;
import org.docx4j.openpackaging.parts.WordprocessingML.ImageJpegPart;
import org.pptx4j.pml.Presentation.SldSz;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.htwg.ppt2html5.util.Sorting;


/**
 * This class extracts needed informations from the given File (PowerPoint presentation).
 * 
 * @author Roman Allenov
 */
public class Extractor implements IExtractor {

   private static Logger         log = LoggerFactory.getLogger(Extractor.class);
   private final File            file;
   private PresentationMLPackage pmlPackage;
   private IInterpreter          interpreter;
   private Presentation          presentation;


   /**
    * Constructor
    * 
    * @param filepath
    *        - the path to the PPT
    * @throws Docx4JException
    */
   public Extractor(File file) {

      this.file = file;
      this.interpreter = new Interpreter();
      this.setPresentation(new Presentation());

      log.info("Extractor received: '{}' ({})", file.getName(), file.getPath());

      try {
         this.pmlPackage = PresentationMLPackage.load(this.file);
      }
      catch (Docx4JException e) {
         log.warn("Extractor failed loading PPT Package.");
      }
   }


   /**
    * this method extracts the needed information for the GUI from the PPT and passes it to the
    * next component in the program.
    * 
    * @param file
    *        - the PPT
    * @throws InvalidFormatException
    */
   public HashMap<String, Object> extractTitleInfo(File receivedPpt)
   {
      // infomap for title GUI
      HashMap<String, Object> infoMap = new HashMap<String, Object>();
      String fileName = "";

      if (receivedPpt != null) {
         fileName = receivedPpt.getName();
      }

      // title of presentation
      String title = pmlPackage.getTitle();
      infoMap.put("title", title);
      try {
         // get thumbnail pic for GUI
         ImageJpegPart thumbnail = (ImageJpegPart)pmlPackage.getParts().get(new PartName(
                                                                                         "/docProps/thumbnail.jpeg"));
         BufferedImage thumbnailPic = ImageIO.read(new ByteArrayInputStream(
                                                                            thumbnail.getBytes()));
         infoMap.put("thumbnail", thumbnailPic);
      }
      catch (InvalidFormatException e) {
         log.warn("Error at fetching thumbnail.");
      }
      catch (IOException e) {
         log.warn("Error at rendering preview.");
      }

      // debug
      log.info("file received (extractor): {}", fileName);
      log.info("ppt title: {}", title);

      return infoMap;

   }


   /**
    * this method initiates the conversion of the PPT.
    */
   public int convert(File saveFile, String alignment)
   {
      // get slides
      List<SlidePart> slidesList = new ArrayList<SlidePart>();
      slidesList = extractSlides(pmlPackage);
      if (!slidesList.isEmpty()) {
         // prepare slides = make new extraction.Slide objects
         setPresentation(interpreter.prepareSlides(pmlPackage, slidesList));

         // trigger html file export
         return interpreter.triggerExport(getPresentation(), saveFile, alignment);
      }
      else {
         log.warn("List of Slides is empty! Therefore PPT has no slides!");
         return 1;
      }
   }


   /**
    * this method extracts the SlidePart objects from the main presentation part and returns a
    * list of SlideParts.
    * 
    * @param pmlPckg
    *        the PresentationML package
    * @return returns a list of slides contained in the PPT
    */
   private List<SlidePart> extractSlides(PresentationMLPackage pmlPckg)
   {

      List<SlidePart> slidePartsList = new ArrayList<SlidePart>();

      // debug
      log.info("parts: {}", pmlPckg.getParts().getParts().size());

      // get slides from the package
      Iterator<Entry<PartName, Part>> iterator = pmlPckg.getParts().getParts().entrySet().iterator();

      while (iterator.hasNext()) {

         Entry<PartName, Part> entry = iterator.next();
         Part part = entry.getValue();

         if (part instanceof SlidePart) {
            slidePartsList.add((SlidePart)part);
         }
      }

      // sort the list for later use
      Sorting.sortList(slidePartsList);

      // debug
      SldSz slideSize = pmlPckg.getMainPresentationPart().getJaxbElement().getSldSz();
      log.info("sizeX " + slideSize.getCx() / 12700 + " sizeY " + slideSize.getCy() / 12700);
      DocPropsCorePart docProps = pmlPckg.getDocPropsCorePart();
      log.info("creator: {}", docProps.getContents().getCreator().getContent().get(0));

      return slidePartsList;
   }


   public PresentationMLPackage getPmlPackage()
   {
      return pmlPackage;
   }


   public void setPmlPackage(PresentationMLPackage pmlPackage)
   {
      this.pmlPackage = pmlPackage;
   }


   public IInterpreter getInterpreter()
   {
      return interpreter;
   }


   public void setInterpreter(IInterpreter interpreter)
   {
      this.interpreter = interpreter;
   }


   public File getFile()
   {
      return file;
   }


   public Presentation getPresentation()
   {
      return presentation;
   }


   public void setPresentation(Presentation presentation)
   {
      this.presentation = presentation;
   }

}
